package com.kklt.kson;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtobufIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.kklt.kson.annotation.KsonScan;
import com.kklt.kson.cache.Cache;
import com.kklt.kson.exception.KsonException;
import com.kklt.kson.util.ClassLoaderUtils;

import java.util.Set;

/**
 * Kson
 * @author lishouyu
 */
public final class Kson {


  /**
   * 将对象序列化成字节
   * @param <T> 要序列化的对象
   * @return
   */
  public static <T> byte[] serialize(T object){
    Class<T> aClass = (Class<T>) object.getClass();
    LinkedBuffer buffer = null;
    try {
      buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
      Schema<T> schema = Kson.getSchema(aClass);
      return ProtobufIOUtil.toByteArray(object, schema, buffer);
    }finally {
      if (buffer!= null){
        buffer.clear();
      }
    }
  }

  /**
   * 反序列化
   * @param bytes 存储对象信息的字节
   * @param cls 对象的类类型
   * @param <T> 对象的类型
   * @return
   */
  public static <T> T deserialize(byte[] bytes,Class<T> cls){
    T message = null;
    try {
      message = cls.newInstance();
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    }
    Schema<T> schema = getSchema(cls);
    ProtobufIOUtil.mergeFrom(bytes,message,schema);
    return message;
  }


  /**
   * 缓存
   * @param cls
   * @param <T>
   * @return
   */
  private static <T> Schema<T> getSchema(Class<T> cls){
    // 从缓存中获取
    Schema<T> schema = (Schema<T>)Cache.get(cls);
    // 缓存中没有就创建,然后填入缓存
    if (schema == null){
      schema = RuntimeSchema.createFrom(cls);
      Cache.put(cls,schema);
    }
    return schema;
  }

  /**
   * 初始化缓存中的Schema
   * @param applicationClass
   */
  public static void init(Class applicationClass){
    boolean annotationPresent = applicationClass.isAnnotationPresent(KsonScan.class);
    if (annotationPresent){
      KsonScan annotation = (KsonScan)applicationClass.getAnnotation(KsonScan.class);
      String[] basePackages = annotation.basePackages();
      if (basePackages != null && basePackages.length>0){
        for (String basePackage : basePackages) {
          Set<Class<?>> classSet = ClassLoaderUtils.getClassSet(basePackage);
          if (classSet!=null && classSet.size()>0){
            classSet.forEach(Kson::getSchema);
          }
        }
      }
    }else {
      throw new KsonException("配置类上无com.kklt.kson.annotation.Kson注解");
    }
  }
}
